import weakref


class Control(object):

    def isOutlet(self, connectionpoint, outlet):
        if hasattr(connectionpoint, 'attachment'):
           if repr(connectionpoint.attachment) == outlet:
               return True
        if hasattr(connectionpoint, 'tag'):
            if connectionpoint.tag == outlet:
                return True
        for connection in connectionpoint.xref:
            if hasattr(connection(), 'caption'):
                if connection().caption == outlet:
                    return True
        return False

    def acquireOutlet(self, event, outlet):
        for connectionpoint in event.shape.xref:
            if self.isOutlet(connectionpoint(), outlet):
                return connectionpoint()

    def acquireInterfaces(self, event, outlet):
        return event.window.acquireInterfaces(event, outlet)

    def acquireInterface(self, event, outlet):
        return (self.acquireInterfaces(event, outlet) + [None])[0]

    def acquireSubcomponents(self, event):
        interest = set()
        for connectionpoint in event.shape.xref:
            for anchor in connectionpoint().xref:
                if isinstance(anchor(), event.window.Point):
                    for anchored in anchor().xref:
                        interest.add(SubBridge(event.window,
                                               connectionpoint, anchored,
                                               event.trail, event.frame))
        return interest

    def getCaption(self, point):
        for connection in point.xref:
            if hasattr(connection(), 'caption'):
                return connection().caption


class Bridge(object):

    def __init__(self, window, source, connector, trail=None, frame=None):
        self.window = weakref.ref(window)
        self.source = source
        self.connector = connector
        self.trail = trail or Trail()
        self.frame = (frame or Frame()).copy()

    def push(self, *args):
        window = self.window()
        source = self.source()
        if window is not None and source is not None:
            for other_side in self.connector().points():
                if other_side is not source:
                    window.emit(other_side.shape(), "incoming",
                                point = other_side, wire = self.connector,
                                trail = self.trail, frame = self.frame,
                                data = args)
        
    def pull(self, *args):
        window = self.window()
        source = self.source()
        if window is not None and source is not None:
            for other_side in self.connector().points():
                if other_side is not source:
                    r = window.call(other_side.shape(), "please",
                                    point = other_side, wire = self.connector,
                                    trail = self.trail, frame = self.frame,
                                    data = args)
                    return r


class SubBridge(Bridge):
    """
    A bridge between a container component and a sub-component.
    In this case, there is no connector between the components, and no target
    connection point at the sub-component, so fake ones are created for
    uniformity of interface.
    """
    class FauxConnector:
        def __init__(self, points):   self.points = lambda: points
        def __call__(self):           return self
    class FauxConnectionPoint:
        def __init__(self, shape):    self.shape = shape

    def __init__(self, window, container_anchor, sub, trail=None, frame=None):
        """
        @param window
        @param container_anchor the connection point at the side of the
          container serving as origin for sub-component
        @param sub weak reference to sub-component
        @param trail
        @param frame
        """
        Bridge.__init__(self,
                        window,
                        container_anchor,
                        self.FauxConnector([container_anchor(),
                                            self.FauxConnectionPoint(sub)]),
                        trail=trail, frame=frame)


class Trail:
    pass


class Frame:
    def __init__(self):
        self.on = { }
    def copy(self):
        clone = Frame()
        clone.on = self.on.copy()
        return clone


class Event(object):
    def __init__(self):
        self.trail = Trail()
        self.frame = Frame()
    def __getattr__(self, attr):
        wattr = "_weak_" + attr
        if wattr in self.__dict__:
            return self.__dict__[wattr]()
        else:
            raise AttributeError, "'%s' object has no attribute '%s'" % \
                    (self.__class__.__name__, attr)
        

